// JQuery的defer对象：等待者模式， https://mp.weixin.qq.com/s/sLn8iJAPsD8S9nBn2rN7EQ

function Waiter(){

    let dtd = [], // 等待队列，装 MyPromise 对象
         doneArr = [], // 成功回调 列表
         failArr = [], // 失败回调 列表
         Slice = [].slice, that = this;

    function MyPromise(){
        this.resoleved = false
        this.rejected = false
    }

    MyPromise.prototype.resolve = function(){
        const args = Slice.call(arguments)
        this.resoleved = true
        for(let i=dtd.length-1; i>=0; i--){
            let promise = dtd[i]
            if(promise&&(!promise.resoleved||promise.rejected)){
                // 存在未成功 或已经失败的promise
                return
            }

            // 从后往前遍历比较好删除
            dtd.splice(i,1)
        }

        // 执行回调,执行异步可以使用setTimeout
        setTimeout(() => {
            execFunc(doneArr,args)
        },0);
    }

    MyPromise.prototype.reject = function(){
        this.rejected = false
        const args = Slice.call(arguments)
        if(!dtd.length){
            return
        }
        // 删除全部元素
        dtd.splice(0)
        setTimeout(()=>{
            execFunc(failArr,args)
        },0)
    }


    that.Defered = function(){
        return new MyPromise()
    }

    that.then = function(onResolve, onRejct){
        // 将不同的回调 加入 对应任务队列
        if(onResolve){
            doneArr.push(onResolve)
        }

        if(onRejct){
            failArr.push(onRejct)
        }

        return that
    }

    that.fail = function(onRejct){
        that.then(null,onRejct)
        return that
    }

    that.when = function(waiters=[]){
        dtd = waiters

        // 清理多余监控对象【可选】
        for( let index=waiters.length-1; index>=0; index-- ){
            if(!dtd[index]|| dtd[index].resoleved|| dtd[index].rejected|| !dtd[index] instanceof MyPromise){
                dtd.splice(index,1)
            }
        }

        return that
    }

    function execFunc(funcArr=[],args){
        for(let func of funcArr){
            try {
                func(args)
            }catch(err){
                console.error(err);
                throw err
            }
        }
    }
}

const waiter = new Waiter()

const firstPromise = waiter.Defered(), secondPromise = waiter.Defered();

console.log(firstPromise);

waiter.when([firstPromise,secondPromise]).then((test)=>{
    console.log(`更好的人: ${test}`);
},(reject)=>{
    console.log(`拒绝： ${reject}`);
})

setTimeout(()=>{
    firstPromise.resolve('qwdnjwqjdk')
},2000)

setTimeout(()=>{
    secondPromise.reject('rejected')
},3000)
